﻿//*********************************************************
//
// Copyright (c) Microsoft. All rights reserved.
// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
//
//*********************************************************
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Expenses;
using Expenses.ExpenseService;
using Windows.UI.Xaml;

namespace Expenses.ViewModels
{
    public class ExpenseItemsViewModel : ViewModelBase
    {
        #region Properties

        private int numberLT30Days = 0;
        public int NumberLT30Days
        {
            get
            { return numberLT30Days; }

            set
            {
                if (numberLT30Days == value)
                { return; }

                numberLT30Days = value;
                RaisePropertyChanged("NumberLT30Days");
            }
        }

        private decimal amountLT30Days = 0M;
        public decimal AmountLT30Days
        {
            get
            { return amountLT30Days; }

            set
            {
                if (amountLT30Days == value)
                { return; }

                amountLT30Days = value;
                RaisePropertyChanged("AmountLT30Days");
            }
        }

        private int number30To44Days = 0;
        public int Number30To44Days
        {
            get
            { return number30To44Days; }

            set
            {
                if (number30To44Days == value)
                { return; }

                number30To44Days = value;
                RaisePropertyChanged("Number30To44Days");
            }
        }

        private decimal amount30To44Days = 0M;
        public decimal Amount30To44Days
        {
            get
            { return amount30To44Days; }

            set
            {
                if (amount30To44Days == value)
                { return; }

                amount30To44Days = value;
                RaisePropertyChanged("Amount30To44Days");
            }
        }

        private int numberGT45Days = 0;
        public int NumberGT45Days
        {
            get
            { return numberGT45Days; }

            set
            {
                if (numberGT45Days == value)
                { return; }

                numberGT45Days = value;
                RaisePropertyChanged("NumberGT45Days");
            }
        }

        private decimal amountGT45Days = 0M;
        public decimal AmountGT45Days
        {
            get
            { return amountGT45Days; }

            set
            {
                if (amountGT45Days == value)
                { return; }

                amountGT45Days = value;
                RaisePropertyChanged("AmountGT45Days");
            }
        }

        public ObservableCollection<SortType> SortTypes { get; set; }

        public int ReportNumber
        {
            get
            {
                return reportNumber;
            }

            set
            {
                if (reportNumber == value)
                {
                    return;
                }

                reportNumber = value;
                RaisePropertyChanged("ReportNumber");

                //update the grouping because the sort/filter type changed
                GroupItems();
            }
        }

        public ObservableCollection<GroupInfoList<object>> GroupedExpenseItems
        {
            get
            {
                return groupedExpenseItems;
            }

            set
            {
                groupedExpenseItems = value;
                RaisePropertyChanged("GroupedExpenseItems");
            }
        }

        public ObservableCollection<ExpenseItemViewModel> ExpenseItems
        {
            get
            {
                return expenseItems;
            }

            set
            {
                expenseItems = value;
                RaisePropertyChanged("ExpenseItems");
            }
        }

        public SortType SortType
        {
            get
            {
                return sortType;
            }

            set
            {
                if (sortType == value)
                {
                    return;
                }

                sortType = value;
                RaisePropertyChanged("SortType");

                //update the grouping because the sort/filter type changed
                GroupItems();
            }
        }

        #endregion

        private SortType sortType = SortType.ItemType;
        private ObservableCollection<GroupInfoList<object>> groupedExpenseItems;
        private ObservableCollection<ExpenseItemViewModel> expenseItems;
        private int reportNumber;

        public ExpenseItemsViewModel()
        {
            this.GroupedExpenseItems = new ObservableCollection<GroupInfoList<object>>();
            this.SortTypes = new ObservableCollection<SortType>();
            this.SortTypes.Add(SortType.Age);
            this.SortTypes.Add(SortType.Amount);
        }

        public async Task<ObservableCollection<ExpenseItemViewModel>>
            GetExpenseItems(int reportNumber)
        {
            var expensesService = new ExpenseServiceClient();
            List<ExpenseItem> outstandingExpenseItems = await
                 expensesService.GetExpenseItemsAsync(reportNumber);

            var expenseItems = from expenseItem in outstandingExpenseItems
                               select new ExpenseItemViewModel()
                               {
                                   Id = expenseItem.Id,
                                   ReportNumber=expenseItem.ReportNumber,
                                   BilledAmount = expenseItem.BilledAmount,
                                   Description = expenseItem.Description,
                                   EmployeeId = expenseItem.EmployeeId,
                                   ExpenseDate = expenseItem.ExpenseDate,
                                   Merchant = expenseItem.Merchant,
                                   Location = expenseItem.Location,
                                   Category = System.Convert.ToInt32(expenseItem.Category),
                                   AccountNumber = System.Convert.ToInt32(expenseItem.AccountNumber),
                                   Notes=expenseItem.Notes,
                                   TransactionAmount = expenseItem.TransactionAmount,
                                   ReceiptRequired = System.Convert.ToBoolean(expenseItem.ReceiptRequired),
                                   ChargeId = expenseItem.ChargeId, 
                                   ExpenseType=Convert.ToInt32(expenseItem.ExpenseType)
                               };
            this.ExpenseItems = new 
                ObservableCollection<ExpenseItemViewModel>(expenseItems);

            this.NumberLT30Days = (from expenseItem in expenseItems
                                   where DateTime.Today.Subtract(expenseItem.ExpenseDate).Days < 30
                                   select expenseItem.BilledAmount).Count();
            this.AmountLT30Days = (from expenseItem in expenseItems
                                   where DateTime.Today.Subtract(expenseItem.ExpenseDate).Days < 30
                                   select expenseItem.BilledAmount).Sum();
            this.Number30To44Days = (from expenseItem in expenseItems
                                     where DateTime.Today.Subtract(expenseItem.ExpenseDate).Days >= 30
                                           && DateTime.Today.Subtract(expenseItem.ExpenseDate).Days < 45
                                     select expenseItem.BilledAmount).Count();
            this.Amount30To44Days = (from expenseItem in expenseItems
                                     where DateTime.Today.Subtract(expenseItem.ExpenseDate).Days >= 30
                                           && DateTime.Today.Subtract(expenseItem.ExpenseDate).Days < 45
                                     select expenseItem.BilledAmount).Sum();
            this.NumberGT45Days = (from expenseItem in expenseItems
                                   where DateTime.Today.Subtract(expenseItem.ExpenseDate).Days >= 45
                                   select expenseItem.BilledAmount).Count();
            this.AmountGT45Days = (from expenseItem in expenseItems
                                   where DateTime.Today.Subtract(expenseItem.ExpenseDate).Days >= 45
                                   select expenseItem.BilledAmount).Sum();

            return this.ExpenseItems;
        }

        public void GroupItems()
        {
            switch (this.SortType)
            {
                case SortType.Age:
                    GroupItemsByTypeAndAge();
                    break;
                case SortType.Amount:
                    GroupItemsByTypeAndAmount();
                    break;
                case SortType.Submitter:
                    GroupItemsBySubmitter();
                    break;
                case SortType.ItemType:
                    GroupItemsByTypeAndAge();
                    break;
                default:
                    break;
            }
        }

        internal GroupInfoList<object> GroupItemsBySubmitter()
        {
            var query = from item in ExpenseItems
                        orderby item.EmployeeId
                        group item by item.EmployeeId into g
                        select new
                        {
                            GroupName = g.Key,
                            Count = g.Count(),
                            Amount = g.Sum(e => e.TransactionAmount),
                            Items = g
                        };

            var groups = new GroupInfoList<object>();
            foreach (var group in query)
            {
                var items = new GroupInfoList<object>();
                //items.Key = string.Format(
                //    "{0} ({1} items for {2:C} USD)", group.GroupName, group.Count, group.Amount);
                items.Key = string.Format(
                    "{0} ({1:C})", group.GroupName, group.Amount);
                items.Amount = System.Convert.ToDecimal(group.Amount);
                foreach (object item in items)
                {
                    items.Add(item);
                }
                groups.Add(items);
            }

            return groups;
        }


        private void GroupItemsByTypeAndAge()
        {
        }

        private void GroupItemsByTypeAndAmount()
        {
        }

    }
}
